﻿package com.cilico.components;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UTFDataFormatException;
import java.util.Vector;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import com.cilico.ConfigManager;
import com.cilico.Mid;
import com.cilico.utils.ConstantRepository;
import com.cilico.utils.HttpManager.CancelIOException;
import com.cilico.utils.Utils;
import com.cilico.view.BaseView;
import com.cilico.view.Channel;

/**
 * 存放poi列表
 * 
 * @author lv.xiangan
 */
public class PoiRepository {

	private final Mid mid_;
	BaseView activity_;
	public String poiXML_;/** Save last POI query string in memory to be saved to RMS */
	// showEntries content xml;
	public String showEntryXml_;
	public int lastSelected_ = -1;
	public String entryUrl_;
	public POI showEntryParent_;
	public int showEntryParentPage_ = 1;

	/** The current channel object used to populate this set of POIs. */
	public Channel channel_;

	/** Remember current channel if we toggle between Favorites and "current". */
	public Channel lastChannel_;

	/**
	 * New POI just added to my favorite channel and the channel which supprot create
	 */
	POI newPoi_;

	// map pin variable
	static Vector<MapPin> mapPinV_;
	static boolean isLoaded_;
	String mapPinCid_; // mappin relate to the channel id.

	// html form action
	public Vector<Object> actionV_;
	static final int ACTION_SIZE = 10;

	public PoiRepository(Mid mid) {
		mid_ = mid;
		channel_ = null;
		poiXML_ = null;
		newPoi_ = null;
	}

	// 设置界面参数
	public void setActivity(BaseView activity) {
		activity_ = activity;
	}

	static final class MapPin {
		String category;// The category of map pin.
		boolean isActive = false;// True if it is an active map pin.
		String url;
		int hotX;
		int hotY;
		Bitmap img = null;

		MapPin(String term, String href, String hot) {
			category = term;
			url = href;
			int idx = -1;
			if (hot != null) {
				idx = hot.indexOf(",");
				if (idx != -1) {
					try {
						hotX = Integer.parseInt(hot.substring(0, idx));
						hotY = Integer.parseInt(hot.substring(idx + 1));
					} catch (Exception ex) {
						idx = -1;
					}
				}
			}
			if (idx == -1) {
				// This means that we don't find hotspot, we will use (w/2,h-3).
				// note's that img is null at begin.
				hotX = Utils.screenWidth_;
				hotY = Utils.screenHeight_;
			}
		}
	}

	static void addMapPin(String term, String type, String url, String hot) {
		if (term != null && type != null && url != null) {
			if (mapPinV_ == null)
				mapPinV_ = new Vector<MapPin>();
			int size = mapPinV_.size();
			MapPin mp = null;
			boolean active = false;
			if (type.equals("active"))
				active = true;
			for (int i = 0; i < size; i++) {
				mp = (MapPin) mapPinV_.elementAt(i);
				// Don't add this mappin if we already have it.
				if (url.equals(mp.url) && term.equals(mp.category) && active == mp.isActive)
					return;
			}
			mp = new MapPin(term, url, hot);
			mp.isActive = active;
			mapPinV_.addElement(mp);
			isLoaded_ = false;
		}
	}

	/**
	 * 执行clear操作，保留一头一尾的内容，删除中间部分
	 */
	void doClearActionPoi() {
		if (null != actionV_) {
			int size = actionV_.size();
			if (size > 3) {
				Vector<Object> vector = new Vector<Object>();
				vector.add(actionV_.elementAt(0));
				vector.add(actionV_.elementAt(1));
				vector.add(actionV_.elementAt(size - 1));
				actionV_.removeAllElements();
				actionV_ = vector;
			}
		}
	}
	
	/**
	 * 执行Refresh操作，保留一头一尾的内容，删除中间部分
	 */
	public void doRefreshActionPOi() {
		// TODO Auto-generated method stub
		if (null != actionV_) {
			int size = actionV_.size();
			if (size > 3) {
				Vector<Object> vector = new Vector<Object>();
				vector.add(actionV_.elementAt(0));
				vector.add(actionV_.elementAt(1));
//				vector.add(actionV_.elementAt(2));
				vector.add(actionV_.elementAt(size - 1));
				actionV_.removeAllElements();
				actionV_ = vector;
			}
		}
	}

	public void removeAllActionPoi() {
		if (actionV_ != null)
			actionV_.removeAllElements();
	}

	/**
	 * get the POI at the top of this vector and remove it from the vector.
	 */
	public Object popActionPoi() {
		if (actionV_ != null && actionV_.size() > 0) {
			int id = actionV_.size() - 1;
			Object p = actionV_.elementAt(id);
			actionV_.removeElementAt(id);
			actionV_.trimToSize();
			return p;
		}
		return null;
	}

	/**
	 * 得到actionV_集合中最上层的poi
	 * 
	 * @return
	 */
	public Object peekActionPoi() {
		if (actionV_ != null && actionV_.size() > 0) {
			int id = actionV_.size() - 1;
			Object p = actionV_.elementAt(id);
			return p;
		}
		return null;
	}

	/**
	 * save a action poi.
	 */
	public void pushActionPoi(Object p) {
		if (actionV_ == null)
			actionV_ = new Vector<Object>();
		if (p != null) {
			actionV_.addElement(p);
			if (actionV_.size() > ACTION_SIZE)
				actionV_.removeElementAt(0);
		}
	}

	/**
	 * Get the quantity of POI
	 */
	public int getActionSize() {
		if (actionV_ != null)
			return actionV_.size();
		else
			return 0;
	}


	/**
	 * NOTE: if parsing fails, we should keep current states intact.
	 */
	public void parsePOIs(Channel channel, String xml) throws Exception {
		// xml = "<?xml version='1.0' encoding='UTF-8'?><!-- This is the xml to test tables, and its channel name will be devTables. --><feed xmlns='http://www.w3.org/2005/Atom'><title>devTables</title><id>1</id><entry><title>Table01 radio</title><description><![CDATA[ <form	action='http://devlt.lightpole.net/buy_fund_success.xml'><table border='1'><tr><td><input type='radio' checked='checked' name='Sex' value='male'></td><td>200</td><td>300</td></tr><tr><td><input type='radio' name='Sex' value='female'></td><td>500</td><td>600</td></tr></table><input type	='submit' value ='Submit'></form> ]]></description></entry><entry><title>Table02 check</title><description><![CDATA[ <form	action='http://devlt.lightpole.net/buy_fund_success.xml'><table border='1'><tr><td><input type='checkbox' name='Car'></td><td>200</td><td>300</td></tr><tr><td><input type='checkbox' name='Bike'></td><td>500</td><td>600</td></tr></table><input type ='submit' value ='Submit'></form> ]]></description></entry></feed>";
		// xml = "<?xml version='1.0' encoding='UTF-8'?><!-- This is the xml to test tables, and its channel name will be devTables. --><feed xmlns='http://www.w3.org/2005/Atom'><title>devTables</title><id>1</id><entry><title>Table01 radio</title><description><![CDATA[ <table border='1'><tr><td><input type='radio' checked='checked' name='Sex' value='male'></td><td>200</td><td>300</td></tr><tr><td><input type='radio' name='Sex' value='female'></td><td>500</td><td>600</td></tr></table><input type	='submit' value ='Submit'> ]]></description></entry><entry><title>Table02 check</title><description><![CDATA[ <table border='1'><tr><td><input type='checkbox' name='Car'></td><td>200</td><td>300</td></tr><tr><td><input type='checkbox' name='Bike'></td><td>500</td><td>600</td></tr></table><input type ='submit' value ='Submit'> ]]></description></entry></feed>";
		if (xml == null)
//			throw new Exception("解析出错，企图解析一个空的数据！");
			throw new Exception("网络数据异常，请稍后再试！");
		Vector<POI> poivec = new Vector<POI>();
		AtomParser parser = BaseView.mid_.parser_;
		// Utf8Checker ckr = new Utf8Checker(xml);
		// ckr.check();
		try {

			if (null == mid_.parser_)
				mid_.parser_ = new AtomParser(mid_);
			mid_.parser_.setPOIProperty(AtomParser.parsePOI_, poivec, channel);
			android.util.Xml.parse(new String(xml.getBytes("UTF-8")), mid_.parser_);
			poivec = mid_.parser_.getPoiVector();
		} catch (Exception ex) {
			// Clear current channel contents to emphasize that this download failed.
			channel.clear();
			Utils.printOutToConsole("PoiRepository-parsePOIs-ex:" + ex.toString());
			// If we failed to parse the XML string, try to interpret error strings.
			throw new IOException(parser.getAppError(xml));
		}
		channel.populate(poivec);
	}

	/**
	 * If force == true, we always load POIs from server. Otherwise we may choose not to load if location has not
	 * changed.
	 */
	public void doReloadPoisInChannel(WaitDialog dlg, boolean force, WaitDialog.Task task, Channel ch, Boolean bl1) throws Exception {
		if (ch != null && (force || ch.updateAtNewLocation())) {
			dlg.setText(ConstantRepository.getWaitText(ConstantRepository.LOADING_DATA));
			downloadPois(ch, task, bl1);
		}
	}

	public void downloadPois(Channel ch, WaitDialog.Task task, Boolean bl1) throws Exception {
		// After downloading, _poiRepo will set this channel to its current channel.
		boolean isTempSelection = false; // this == mid_.lastValidPoiRepo_;
		try {
			downloadFromServer(ch, task, bl1);
			mid_.getCurrentPoiSelection(isTempSelection, activity_).populate(this);
		} catch (CancelIOException cex) {
			throw (cex);
		} catch (Exception ex) {
			PoiSelection s = mid_.getCurrentPoiSelection(false, activity_);
			if (s != null)
				s.removeAllElements();
			throw (ex);
		}
	}

	void downloadFromServer(Channel ch, WaitDialog.Task task, Boolean bl1) throws Exception {
		poiXML_ = null;
		channel_ = ch;
		downloadChannelLogoImg(channel_);
		downloadChannelPOIs(channel_, channel_.queryString_, task, bl1);
	}


	/**
	 * Download channel logo image if this channel has a logo.
	 */
	void downloadChannelLogoImg(Channel channel) throws Exception {
		if (channel.logoUrl_ != null && channel.titleImg_ == null) {
			StringBuffer url = new StringBuffer(ConfigManager.SERVER_URI);
			url.append(channel.logoUrl_.substring(1));
			url.append("&sw=");
			url.append(Integer.toString(Utils.screenWidth_));
			url.append("&sh=");
			url.append(Integer.toString(Utils.screenHeight_));
			ByteArrayOutputStream imageBuffer = new ByteArrayOutputStream(1024);
			mid_.hm_.read(url.toString(), imageBuffer, null);
			byte[] imageBytes = imageBuffer.toByteArray();
			imageBuffer.close();
			Bitmap image = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
			channel.titleImg_ = image;
		}
	}

	/**
	 * Download POIs of a given channel from package manager (either from server or offline package.) Return false if
	 * this channel needs not to be updated.
	 * 
	 */
	protected void downloadChannelPOIs(Channel channel, String query, WaitDialog.Task task, Boolean bl1) throws Exception {
		StringBuffer body = new StringBuffer();
		StringBuffer mainURL = new StringBuffer();
		String channelurl = channel.getChannelUrl();
		if (!channelurl.startsWith("http://"))
			mainURL.append(ConfigManager.SERVER_URI);
		int index = channelurl.indexOf("?");
		if (index != -1) {
			mainURL.append(channelurl.substring(0, index));
			body.append(channelurl.substring(index + 1));
		}
	

		// NOTE: we must escape the query string, so that it does not mess up our own CGI parameters.
		if (query != null && query != "") {
			body.append("&querystr=");
			body.append(Utils.escapeURIComponent(query));
		}
		body.append("&p=");
		// This uses the channel's native paging object instead of display paging.
		body.append(channel.paging_.downloadPage_);
		try {
			if (channel.paging_.downloadPage_ == 1)
				clearMapPin(channel);
			String desBody = body.toString();
			String reply = (String) mid_.hm_.sendPostRequest(mainURL.toString(), desBody, task, null, null);
			// 手机充值首页
//			String reply = Utils.getStringFormAsset(ConfigManager.currentView_, "xmlview/detailview.xml"); 
			// 登录页面(修改测试用） xmlview/loginview
//			String reply = Utils.getStringFormAsset(ConfigManager.currentView_, "test.xml"); // 我的绿卡
			reply = new String(reply.getBytes("UTF-8"));
			parsePOIs(channel, reply);
			poiXML_ = reply;
			showEntryXml_ = null;
			downloadMapPinImg();
		} catch (UTFDataFormatException ex) {
			// If we have an incomplete download, it's likely that we get garbled
			// data, hence this exception. Convert it to a more readable format.
			Utils.printOutToConsole("PoiRepository-downloadChannelPOIs-ex:" + ex.toString());
			throw new IOException("下载数据时网络被中断.");
		} catch (Exception ex) {
			Utils.printOutToConsole("PoiRepository-downloadChannelPOIs-ex:" + ex.toString());
			throw ex;
		} catch (Error err) {
			Utils.printOutToConsole("PoiRepository-downloadChannelPOIs-err:" + err.toString());
		}
	}
	/**
	 * 根据LPImageItem中isEdit_的状态发送不同的请求 true是发送删除请求，false是发送详细页面的请求
	 * @author lvke
	 * Email: lvke@live.cn
	 * 2014-1-4下午1:12:52
	 * @param activity
	 * @param url
	 * @param task
	 * @throws Exception
	 */
	public void downloadChannelPOIs(BaseView activity, String url, WaitDialog.Task task) throws Exception { 
		String body = null;
		if (url != null){
			if (url.startsWith("lp:")) {
				url = "http" + url.substring(2);
				int index = url.indexOf("?");
				if (index != -1) {
					body = url.substring(index + 1);
					url = url.substring(0, index);
				}
				Utils.printOutToConsole("+++ dealWithLink() +++ body:\n" + body);
				// add _s for the controllers.
				String temphost = null;
				int indexC = url.indexOf("/channel/");
				int indexA = url.indexOf("/atompub/");
				if (indexC != -1) {
					temphost = url.substring(0, indexC) + "/channel_s/" + url.substring(indexC + "/channel/".length());
				} else if (indexA != -1) {
					temphost = url.substring(0, indexA) + "/atompub_s/"  + url.substring(indexA + "/atompub/".length());
				}
				if (temphost != null)
					url = temphost;
				Utils.printOutToConsole("+++ dealWithLink() +++ body:\n" + body);
			}
		}
		
		try {
			// 把加载channel的请求都变成加密。
			String reply = (String) mid_.hm_.sendPostRequest(url, body, task, null, null);
			BaseView.mid_.parserLoginMessage(activity, reply);
			mid_.channelRepo_.downloadChannelListSuccess();
			poiXML_ = reply;
			showEntryXml_ = null;
		} catch (UTFDataFormatException ex) {
			Utils.printOutToConsole("PoiRepository-downloadChannelPOIs-ex:" + ex.toString());
			throw new IOException("下载数据时网络被中断.");
		} catch (Exception ex) {
			Utils.printOutToConsole("PoiRepository-downloadChannelPOIs-ex:" + ex.toString());
			throw ex;
		} catch (Error err) {
			Utils.printOutToConsole("PoiRepository-downloadChannelPOIs-err:" + err.toString());
		}
	}
	
	void clearMapPin(Channel c) {
		if (mapPinV_ == null)
			return;
		// If channel is not changed we don't clear mappin.
		if (c != null && c.id().equals(mapPinCid_))
			return;
		MapPin mp;
		for (int i = 0; i < mapPinV_.size(); i++) {
			mp = (MapPin) mapPinV_.elementAt(i);
			mp.category = null;
			mp.img = null;
			mp.url = null;
		}
		mp = null;
		mapPinV_.removeAllElements();
	}

	private void downloadMapPinImg() throws Exception {
		mapPinCid_ = channel_.id();
		if (mapPinV_ != null && !isLoaded_) {
			int size = mapPinV_.size();
			MapPin mp;
			ByteArrayOutputStream buf = new ByteArrayOutputStream(1024);
			for (int i = 0; i < size; i++) {
				mp = (MapPin) mapPinV_.elementAt(i);
				// we may have downloaded this map pin.
				if (mp.img == null) {
					mid_.hm_.read(mp.url, buf, null);
					mp.img = BitmapFactory.decodeByteArray(buf.toByteArray(), 0, buf.size());
					buf.reset();
				}
			}
			buf.close();
			isLoaded_ = true;
		}
	}

	POI newPoi() {
		if (newPoi_ != null) {
			return newPoi_;
		} else {
			return null;
		}
	}

	POI getPOI(int idx) {
		return (idx < 0 || idx >= channel_.size()) ? null : (POI) channel_.poiList_.elementAt(idx);
	}

	int size() {
		return channel_.size();
	}

}
